﻿module SVMExec

open SVMTypes
open SVMInstructions


let exec_instruction  (current_state : SVM) 
                      (ins : Instruction) 
                      (arg1 : Option<string>)
                      (arg2 : Option<string>) : Option<SVM> * string =
  
  let call (current_state : SVM) (args : string list) (ins : Instruction) : Option<SVM> * string =
    match ins.OpCode with
    | 00000000L -> nop current_state
    | 00000001L -> load current_state (List.nth args 0) (List.nth args 1)
    | _ -> failwith "BUG in exec_instruction, opcode should have already been checked" 
  
  match arg1 with
  | None -> call current_state [] ins
  | Some a1 ->
      match ins.Arg1 with
      | None -> failwith "BUG in exec_instruction, number of operand should have already been checked"
      | Some arg_list -> 
          if arg_list |> Seq.exists(fun t -> t = (get_type a1)) then
            match arg2 with
            | None -> call current_state [a1] ins
            |Some a2 ->
              match ins.Arg2 with
              | None -> failwith "BUG in exec_instruction, number of operand should have already been checked"
              | Some arg_list ->
                  if arg_list |> Seq.exists(fun t -> t = (get_type a2)) then
                    call current_state [a1;a2] ins
                  else
                    None,"Second argument does not match operand type"
          else
            None,"First argument does not match operand type"
